home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / progjrn / pj_7_3a.arc / CUT.C < prev    next >
C/C++ Source or Header  |  1989-04-19  |  7KB  |  333 lines

  1. /*
  2.  *  cut.c    - a unix like filter
  3.  *
  4.  *  Author:                M. Steven Baker
  5.  *  Last Revision:        October 17, 1988
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12.  
  13. #ifndef FILENAME_MAX
  14. #define FILENAME_MAX    68
  15. #endif
  16.  
  17. FILE *infp;
  18. FILE *outfp = stdout;                /* our file pointers */
  19.  
  20. char  infile[FILENAME_MAX] = "";    /* our file names */
  21. char outfile[FILENAME_MAX] = "";
  22.  
  23. int verbose = 0;
  24. int    errflag = 0;
  25.  
  26. char delim = '\t';            /* default delimiter character */
  27. int fieldflag = 0;            /* logical flag for field delimited cut */
  28. int colflag = 0;            /* logical flag fro column oriented cut */
  29. int sflag = 0;                /* the cut -s flag -- not implemented yet */
  30.  
  31. char *pgm = "cut";        /* our program name */
  32.  
  33. #define MAXLINE    8192
  34.  
  35. char map[MAXLINE+2];        /* our field map array */
  36. char line [MAXLINE+2];        /* our fgets() line buffer */
  37.  
  38. void usage();
  39.  
  40. char *help_msg[] = {
  41.     "CUT various columns or fields from an ascii text file.",
  42.     "The following options may be used singly or in combination:",
  43.     "-c columns \t cut columns (ie 1,2,5,7-20)",
  44.     "-d delimiter \t field delimiter character (default = tab)",
  45.     "-f fields \t cut fields (ie 1,2,5,12-30)",
  46.     "-o filename\t create output text file (default stdout)",
  47. /*    "-s \t\t don't copy lines without delimiters" , */
  48.     "-v\t\t verbose mode"
  49. };
  50.  
  51. main(argc,argv)
  52. int argc;
  53. char **argv;
  54. {
  55.     int    ch;                    /* variable for getopt */
  56.     int i;
  57.  
  58.     extern int getopt();
  59.     extern char *optarg;
  60.     extern int optind, opterr;
  61.  
  62.     for (i = 0; i < MAXLINE; i++)    map[i] = 0;        /* zero map array */
  63.  
  64.     /* process command-line arguments */
  65.     opterr = 0;    /* first turn off error messages from getopt */
  66.     while ((ch = getopt(argc,argv, "vsc:d:f:o:")) != EOF)
  67.     {
  68.         switch (ch) {
  69.             case 'c':
  70.                 colflag = 1;
  71.                 if (setfields(optarg) == EOF) {
  72.                     errflag++;
  73.                     if (verbose)
  74.                         fprintf(stderr,"%s: Error setting columns to cut\n",pgm);
  75.                 }
  76.                 break;
  77.             case 'd':
  78.                 delim = *optarg;
  79.                 break;
  80.             case 'f':
  81.                 fieldflag = 1;
  82.                 if (setfields(optarg) == EOF) {
  83.                     errflag++;
  84.                     if (verbose)
  85.                         fprintf(stderr,"%s: Error setting fields to cut\n",pgm);
  86.                 }
  87.                 break;
  88.             case 'v':
  89.                 verbose = 1;
  90.                 break;
  91.             case 'o':        /* output specifed cut text file */
  92.                 strcpy(outfile, optarg);
  93.                 outfp = NULL;
  94.                 break;
  95.             case 's':        /* not implemented */
  96.                 sflag = 1;
  97.                 break;
  98.             default:        /* unknown option */
  99.                 errflag++;
  100.                 break;
  101.             }
  102.         }
  103.     if (colflag && fieldflag) errflag++;    /* can't have both options */
  104.  
  105.     if (errflag || !(argc-optind) ) {
  106.         usage(pgm);
  107.         exit(1);
  108.     }
  109.     if ( dofiles(argc - optind, argv += optind) )    /* did we have errors? */
  110.         exit (1);
  111.  
  112.     exit(0);
  113. }
  114.  
  115. /*
  116.  *    dofiles -  process each filename or standard input
  117.  */
  118.  
  119. int dofiles(ac, av)
  120. int    ac;
  121. char **av;
  122. {
  123.     int    ch, errcount = 0;
  124.     char *p;
  125.  
  126.     for (; ac > 0; --ac, ++av) {
  127.         p = *av;
  128.         strcpy(infile,p);            /* store binary data filename */
  129.         if ((infp = fopen (infile,"rt")) == NULL) {
  130.             fprintf(stderr,"%s: ERROR opening input file: %s\n",
  131.             pgm,infile);
  132.             continue;
  133.         }
  134.         if (outfp != stdout) {
  135.             if ((outfp = fopen (outfile,"wt")) == NULL) {
  136.                 fprintf(stderr,"%s: ERROR opening output file: %s\n",pgm,outfile);
  137.                 fclose (infp);
  138.                 continue;
  139.             }
  140.         }
  141.         if (cut(infp,outfp)== EOF) {
  142.             fprintf(stderr,"%s: Error converting file: %s\n",pgm,infile);
  143.             fclose(infp);
  144.             fclose(outfp);
  145.             errcount++;
  146.             continue;
  147.         }
  148.         fclose(infp);
  149.         if (fclose(outfp) == EOF) {
  150.             fprintf(stderr,"%s: Error closing output file: %s\n",pgm,outfile);
  151.             errcount++;
  152.             continue;
  153.         }
  154.     }                    /* end of for loop */
  155.     return (errcount);
  156. }
  157.  
  158. /*
  159.  *  do the actual cut
  160.  */
  161.  
  162. cut(fp1,fp2)
  163. FILE *fp1, *fp2;
  164. {
  165.     int i;
  166.     char c;
  167.     char *p;
  168.  
  169.     while ((p = fgets(line, MAXLINE+2, fp1)) != NULL) {
  170.         i = 0;
  171.         for (c = *p; *p; c = *++p) {
  172.             if (fieldflag) {
  173.                 if (map[i] || c == '\n') fputc(c,fp2);
  174.                 if (c == delim) i++;
  175.             }
  176.             else {
  177.                 if (colflag) {
  178.                     if (map[i++] || c == '\n') fputc(c,fp2);
  179.                 }
  180.                 else fputc(c,fp2);
  181.             }
  182.         }
  183.     }
  184.     return (0);
  185. }
  186.  
  187. #define BEGIN    0
  188. #define NUMBER    1
  189. #define COMMA    2
  190. #define RANGE    3
  191.  
  192. /*
  193.  *    setfields - set fields to cut from command line
  194.  */
  195.  
  196. int setfields(optarg)
  197. char *optarg;
  198. {
  199.     int i, last, state;
  200.     char c;
  201.     char *p;
  202.  
  203.     i = last = state = BEGIN;
  204.     p = optarg;
  205.  
  206.     if ((c =*p) == '\0') return (EOF);
  207.  
  208.     while ((c = *p) && i < MAXLINE) {
  209.         switch (state) {
  210.             case BEGIN:
  211.                 i =stoi(&p);                /* now pointing to next char */
  212.                 if (i > 0 && i < MAXLINE) {
  213.                     last = i;
  214.                     map[i-1] =1;
  215.                     state = NUMBER;
  216.                 }
  217.                 else return (EOF);
  218.                 break;
  219.             case NUMBER:                /* a number was last */
  220.                 if ( c == '-')
  221.                     state = RANGE;
  222.                 else {
  223.                     if (c == ',')    state = COMMA;
  224.                     else return (EOF);
  225.                 }
  226.                 p++;                    /* increment pointer */
  227.                 break;
  228.             case COMMA:
  229.                 if (isdigit(c)) {
  230.                     i = stoi(&p);        /* stoi increments pointer */
  231.                     if (i > 0 && i < MAXLINE) {
  232.                         last = i;
  233.                         map[i-1] = 1;
  234.                         state = NUMBER;
  235.                     }
  236.                     else return (EOF);
  237.                 }
  238.                 else return (EOF);
  239.                 break;
  240.             case RANGE:
  241.                 if (isdigit(c)) {
  242.                     i = stoi(&p);            /* stoi increments pointer */
  243.                     if (i > 0 && i < MAXLINE) {
  244.                         if (last < i) {
  245.                             while (last < i)
  246.                                 map[++last -1] = 1;
  247.                             state = NUMBER;
  248.                         }
  249.                         else return (EOF);
  250.                     }
  251.                     else return (EOF);
  252.                 }
  253.                 else return (EOF);
  254.                 break;
  255.             default:
  256.                 return (EOF);
  257.         }
  258.     }
  259.     return (0);
  260. }
  261.  
  262. /* STOI.C    More powerful version of atoi.
  263.  *
  264.  *    chopped from the Allen Holub stoi(c)
  265.  *    
  266.  */
  267.  
  268. int        stoi(instr)
  269. char    **instr;
  270. {
  271.     /*    Convert string to integer. If string starts with 0x it is
  272.      *    interpreted as a hex number, else if it starts with a 0 it
  273.      *    is octal, else it is decimal. Conversion stops on encountering
  274.      *    the first character which is not a digit in the indicated
  275.      *    radix. *instr is updated to point past the end of the number.
  276.  
  277.      *  patched to ignore leading '-' sign, since we need this for range
  278.      */
  279.  
  280.     int    num  = 0 ;
  281.     char *str = *instr;
  282.  
  283.     while( isspace(*str) )
  284.         str++ ;
  285.     if(*str == '0') {
  286.         ++str;
  287.         if (*str == 'x'  ||  *str == 'X') {
  288.             str++;
  289.             while(  ('0'<= *str && *str <= '9') ||
  290.                 ('a'<= *str && *str <= 'f') ||
  291.                 ('A'<= *str && *str <= 'F')  )
  292.             {
  293.                 num *= 16;
  294.                 num += ('0'<= *str && *str <= '9') ?
  295.                     *str - '0'            :
  296.                     toupper(*str) - 'A' + 10   ;
  297.                 str++;
  298.             }
  299.         }
  300.         else {
  301.             while( '0' <= *str  &&  *str <= '7' ) {
  302.                 num *= 8;
  303.                 num += *str++ - '0' ;
  304.             }
  305.         }
  306.     }
  307.     else {
  308.         while( '0' <= *str  &&  *str <= '9' ) {
  309.             num *= 10;
  310.             num += *str++ - '0' ;
  311.         }
  312.     }
  313.  
  314.     *instr = str;
  315.     return( num );
  316. }
  317.  
  318. /*
  319.  *    usage - display an abbreviated help usage message
  320.  */
  321.  
  322. void usage(pname)
  323. char *pname;
  324. {
  325.     int i, n = sizeof(help_msg)/sizeof (char *);
  326.  
  327.     fprintf(stderr,"Usage: %s [options] file...\n\n",pname);
  328.     for (i = 0; i < n; ++i)
  329.         fprintf(stderr, "%s\n",help_msg[i]);
  330.     return;
  331. }
  332.  
  333.